package com.tcm.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tcm.common.enums.CachePrefix;
import com.tcm.config.AppProperties;
import com.tcm.entity.*;
import com.tcm.entity.bo.UserCacheBo;
import com.tcm.entity.dto.param.CollectUpdateParam;
import com.tcm.entity.resp.PageR;
import com.tcm.entity.vo.BookListResult;
import com.tcm.entity.vo.CollectDetailResp;
import com.tcm.entity.vo.CollectListResult;
import com.tcm.exception.EntityAlreadyExistException;
import com.tcm.mapper.BookItemMapper;
import com.tcm.mapper.TeacherMapper;
import com.tcm.service.*;
import com.tcm.mapper.CollectMapper;
import com.tcm.utils.RedisUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 学生题目收藏业务实现类
* @author Guqier
* @description 针对表【ts_collect(题目收藏表)】的数据库操作Service实现
* @createDate 2023-08-20 16:52:10
*/
@Service
public class CollectServiceImpl extends ServiceImpl<CollectMapper, Collect>
    implements CollectService{

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private SubjectItemService subjectItemService;

    @Autowired
    private ClozeItemService clozeItemService;

    @Autowired
    private BookService bookService;

    @Autowired
    private BookItemMapper bookItemMapper;

    @Autowired
    private CodeService codeService;

    @Autowired
    private ImageService imageService;

    @Autowired
    private ItemService itemService;

    @Autowired
    private TeacherMapper teacherMapper;

    @Autowired
    private RoleService roleService;

    @Autowired
    private UserService userService;

    /**
     * 添加是收藏
     * @param param 收藏更新参数
     * @param currUserId 当前登录用户ID
     * @return 添加结果，true为成功，false是保存失败
     */
    @Override
    @Transactional
    public boolean addCollect(CollectUpdateParam param, Long currUserId){
        // 获取学生信息
        UserCacheBo userCacheBo = redisUtil.getCacheObject(CachePrefix.PC_USER_TOKEN.getCacheKey(currUserId.toString()));
        // 校验收藏是否已存在
        LambdaQueryWrapper<Collect> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Collect::getAccount, userCacheBo.getAccount()).eq(Collect::getItemId, param.getItemId());
        if (this.count(queryWrapper) != 0) {
            throw new EntityAlreadyExistException("该题目已收藏");
        }
        // 构造实体
        Collect collect = new Collect();
        collect.setAccount(userCacheBo.getAccount());
        collect.setType(param.getType());
        collect.setItemId(param.getItemId());
        collect.setTime(new Date());
        collect.setCreateUser(currUserId);
        collect.setUpdateUser(currUserId);
        return this.save(collect);
    }

    /**
     * 取消收藏
     * @param itemId 题目ID
     * @param currUserId 当前用户ID
     * @return 删除结果，true为成功
     */
    @Override
    @Transactional
    public boolean canselCollect(Long itemId, Long currUserId){
        // 获取学生信息
        UserCacheBo userCacheBo = redisUtil.getCacheObject(CachePrefix.PC_USER_TOKEN.getCacheKey(currUserId.toString()));
        LambdaQueryWrapper<Collect> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Collect::getAccount, userCacheBo.getAccount());
        queryWrapper.eq(Collect::getItemId, itemId);
        return this.remove(queryWrapper);
    }

    /**
     * 学生获取收藏列表
     * @param currUserId 当前登录用户ID
     * @return 收藏列表
     */
    @Override
    public List<CollectListResult> getStuCollectList(Long currUserId){
        // 获取学生信息
        UserCacheBo userCacheBo = redisUtil.getCacheObject(CachePrefix.PC_USER_TOKEN.getCacheKey(currUserId.toString()));
        // 查询当前学生所有收藏
        LambdaQueryWrapper<Collect> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Collect::getAccount, userCacheBo.getAccount());
        queryWrapper.orderByDesc(Collect::getUpdateTime);
        List<Collect> collects = this.list(queryWrapper);

        return this.transferCollectToListResult(collects);
    }

    /**
     * 获取收藏详细
     * @param current 当前数
     * @param currUserId 当前用户ID
     * @return 收藏详细
     */
    @Override
    public PageR<CollectDetailResp> getCollectDetail(Integer current, Long currUserId){
        // 获取学生信息
        UserCacheBo userCacheBo = redisUtil.getCacheObject(CachePrefix.PC_USER_TOKEN.getCacheKey(currUserId.toString()));
        // 构造查询条件
        Page<Collect> page = new Page<>(current, 1);
        page.addOrder(OrderItem.desc("update_time"));
        LambdaQueryWrapper<Collect> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Collect::getAccount, userCacheBo.getAccount());
        // 查询收藏
        this.page(page, queryWrapper);
        // 准备数据
        List<Book> books = bookService.getBookList();
        // 构造结果集
        PageR<CollectDetailResp> pageR = new PageR<>();
        BeanUtils.copyProperties(page, pageR, "records");
        Collect collect = page.getRecords().get(0);
        CollectDetailResp collectDetailResp = new CollectDetailResp();
        if (collect.getType().equals(AppProperties.ITEM_TYPE_SUBJECT)) {
            SubjectItem subjectItem = subjectItemService.getSubjectItemById(collect.getItemId());
            List<BookItem> bookItems = bookItemMapper.selectList(new LambdaQueryWrapper<BookItem>().eq(BookItem::getItemId, subjectItem.getId()));
            // 查询章节
            List<BookListResult> bookListResults = bookService.getBooksOfItem(subjectItem.getId(), bookItems, books).get(0);
            Collections.reverse(bookListResults);
            collectDetailResp.setChapter(bookListResults.stream().map(BookListResult::getName).collect(Collectors.joining("/")));
            // 封装其他信息
            collectDetailResp.setId(subjectItem.getId());
            collectDetailResp.setType(collect.getType());
            collectDetailResp.setGender(subjectItem.getGender());
            collectDetailResp.setAge(subjectItem.getAge());
            Code difficulty = codeService.getById(subjectItem.getDifficultyId());
            collectDetailResp.setDifficulty(difficulty != null ? difficulty.getName() : null);
            collectDetailResp.setKnowledgePoints(Arrays.asList(subjectItem.getKnowledgePoint().split("\\|")));
            collectDetailResp.setContent(subjectItem.getContent());
            // 是否收藏
            collectDetailResp.setIsCollect(1);
            // 查询关联图片
            List<Image> images = imageService.getImagesByItemId(subjectItem.getId());
            collectDetailResp.setImages(images.stream().map(Image::getRemoteFileUrl).collect(Collectors.toList()));
            // 获取总分
            collectDetailResp.setScore(itemService.calculateItemTotalScore(subjectItem));
            // 构造问题，计算总分
            List<CollectDetailResp.SubjectQuestion> questions = new ArrayList<>();
            if (StringUtils.hasText(subjectItem.getAnsDiagnose())) {
                questions.add(new CollectDetailResp.SubjectQuestion("diagnose", "请诊断该患者的病症是什么？", Arrays.asList(subjectItem.getTipDiagnose().split("\\|")), subjectItem.getAnsDiagnose()));
            }
            if (StringUtils.hasText(subjectItem.getAnsCause())){
                questions.add(new CollectDetailResp.SubjectQuestion("cause", "请问该患者的病机是什么？", Arrays.asList(subjectItem.getTipCause().split("\\|")), subjectItem.getAnsCause()));
            }
            if (StringUtils.hasText(subjectItem.getAnsMethod())){
                questions.add(new CollectDetailResp.SubjectQuestion("method", "请问该患者的治法是什么？", Arrays.asList(subjectItem.getTipMethod().split("\\|")), subjectItem.getAnsMethod()));
            }
            if (StringUtils.hasText(subjectItem.getAnsPrescription())){
                questions.add(new CollectDetailResp.SubjectQuestion("prescription", "请问该患者开的处方是什么？", Arrays.asList(subjectItem.getTipPrescription().split("\\|")), subjectItem.getAnsPrescription()));
            }
            if (StringUtils.hasText(subjectItem.getAnsMedicine())){
                questions.add(new CollectDetailResp.SubjectQuestion("medicine", "请问该患者开的药物是什么？", Arrays.asList(subjectItem.getTipMedicine().split("\\|")), subjectItem.getAnsMedicine()));

            }
            collectDetailResp.setQuestions(questions);
            collectDetailResp.setTime(collect.getTime());
        }else {
            ClozeItem clozeItem = clozeItemService.getClozeItemById(collect.getItemId());
            List<BookItem> bookItems = bookItemMapper.selectList(new LambdaQueryWrapper<BookItem>().eq(BookItem::getItemId, clozeItem.getId()));
            collectDetailResp.setId(clozeItem.getId());
            // 查询难易级别
            Code difficulty = codeService.getById(clozeItem.getDifficultyId());
            collectDetailResp.setDifficulty(difficulty != null ? difficulty.getName() : null);
            collectDetailResp.setKnowledgePoints(Arrays.asList(clozeItem.getKnowledgePoint().split("\\|")));
            collectDetailResp.setContent(clozeItem.getMarkContent());
            collectDetailResp.setType(collect.getType());
            // 查询是否收藏
            collectDetailResp.setIsCollect(1);
            // 查询关联图片
            List<Image> images = imageService.getImagesByItemId(clozeItem.getId());
            collectDetailResp.setImages(images.stream().map(Image::getRemoteFileUrl).collect(Collectors.toList()));
            // 计算总分
            collectDetailResp.setScore(itemService.calculateItemTotalScore(clozeItem));
            // 查询章节
            List<BookListResult> bookListResults = bookService.getBooksOfItem(clozeItem.getId(), bookItems, books).get(0);
            Collections.reverse(bookListResults);
            collectDetailResp.setChapter(bookListResults.stream().map(BookListResult::getName).collect(Collectors.joining("/")));
            collectDetailResp.setTime(collect.getTime());
            collectDetailResp.setAns(clozeItem.getAns());
        }
        pageR.setRecords(new ArrayList<CollectDetailResp>(){{
            add(collectDetailResp);
        }});
        return pageR;
    }

    /**
     * 将收藏实体类转换为列表展示类
     * @param collects 列表实体类集合
     * @return 列表展示类集合
     */
    private List<CollectListResult> transferCollectToListResult(List<Collect> collects){
        List<Long> ids = collects.stream().map(Collect::getItemId).collect(Collectors.toList());
        // 将收藏分类
        List<Collect> subjectCollect = collects.stream().filter(collect -> collect.getType().equals(AppProperties.ITEM_TYPE_SUBJECT)).collect(Collectors.toList());
        List<Collect> clozeCollect = collects.stream().filter(collect -> collect.getType().equals(AppProperties.ITEM_TYPE_CLOZE)).collect(Collectors.toList());
        // 获取收藏题目
        List<SubjectItem> subjectItems;
        if (!CollectionUtils.isEmpty(subjectCollect)) {
            subjectItems = subjectItemService.getBaseMapper().selectBatchIds(subjectCollect.stream().map(Collect::getItemId).collect(Collectors.toList()));
        } else {
            subjectItems = Collections.emptyList();
        }
        List<ClozeItem> clozeItems;
        if (!CollectionUtils.isEmpty(clozeCollect)){
            clozeItems = clozeItemService.getBaseMapper().selectBatchIds(clozeCollect.stream().map(Collect::getItemId).collect(Collectors.toList()));
        }else {
            clozeItems = Collections.emptyList();
        }
        // 准备数据
        List<BookItem> bookItems = bookItemMapper.selectList(new LambdaQueryWrapper<BookItem>()
                .in(!CollectionUtils.isEmpty(ids), BookItem::getItemId, ids)
                .apply(CollectionUtils.isEmpty(ids), "1 != 1"));
        List<Book> books = bookService.getBookList();
        // 构造结果集
        return collects.stream().map(collect -> {
            CollectListResult result = new CollectListResult();
            result.setAccount(collect.getAccount());
            BeanUtils.copyProperties(collect, result);
            if (collect.getType().equals(AppProperties.ITEM_TYPE_SUBJECT)) {
                subjectItems.stream().filter(subjectItem -> subjectItem.getId().equals(collect.getItemId())).findFirst().ifPresent(subjectItem -> {
                    result.setContent(subjectItem.getContent());
                    List<BookListResult> bookList = bookService.getBooksOfItem(subjectItem.getId(), bookItems, books).get(0);
                    Collections.reverse(bookList);
                    result.setChapter(bookList.stream().map(BookListResult::getName).collect(Collectors.joining("/")));
                });
            } else if (collect.getType().equals(AppProperties.ITEM_TYPE_CLOZE)) {
                clozeItems.stream().filter(clozeItem -> clozeItem.getId().equals(collect.getItemId())).findFirst().ifPresent(clozeItem -> {
                    result.setContent(clozeItem.getMarkContent());
                    List<BookListResult> bookList = bookService.getBooksOfItem(clozeItem.getId(), bookItems, books).get(0);
                    Collections.reverse(bookList);
                    result.setChapter(bookList.stream().map(BookListResult::getName).collect(Collectors.joining("/")));
                });
            }
            return result;
        }).collect(Collectors.toList());
    }

    @Override
    public PageR<CollectListResult> getCollectListByTeacher(Integer page, Integer pageSize, String account,Long currUserId, String currAccount){
        Page<Collect> collectPage = new Page<>(page, pageSize);
        collectPage.addOrder(OrderItem.desc("create_time"));

        // 构造查询条件
        LambdaQueryWrapper<Collect> queryWrapper = new LambdaQueryWrapper<>();
        if (!roleService.isAdministrator(currUserId)) {// 如果不是管理员则仅可以查看自己所教班级的数据
            List<String> accounts = teacherMapper.selectStudentAccountByTeacherAccount(currAccount);
            queryWrapper.in(!CollectionUtils.isEmpty(accounts), Collect::getAccount, accounts);
            queryWrapper.apply(CollectionUtils.isEmpty(accounts), "1 != 1");
        }
        queryWrapper.eq(StringUtils.hasText(account), Collect::getAccount, account);
        this.page(collectPage, queryWrapper);

        // 构造结果集
        PageR<CollectListResult> pageR = new PageR<>();
        BeanUtils.copyProperties(collectPage, pageR, "records");

        List<CollectListResult> collectListResults = this.transferCollectToListResult(collectPage.getRecords());
        collectListResults.forEach(collectListResult -> {
            User user = userService.getUserByAccount(collectListResult.getAccount());
            collectListResult.setName(user.getName());
            Optional.ofNullable(user.getAvatar()).ifPresent(id -> collectListResult.setAvatarUrl(imageService.getImageById(id).getRemoteFileUrl()));
        });
        pageR.setRecords(collectListResults);
        return pageR;
    }
}




